
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>
#include "usb_fp_protocol.h"
#include "common.h"
#include "uapi_usb.h"
#include "ofp_config.h"
#include "ofp_dev.h"
#include "ofp_tools.h"
#include "ofp_storage.h"


ofp_dev *g_ofp_dev;


static const ofp_tool_operation g_ofp_tool_operation[TOOLS_OPS_MAX] = {
    {TOOLS_HELP_OPS, "help", "display usage"},
    {TOOLS_GET_FIRMWARE_VERSION_OPS, "version", "get firmware version"},
    {TOOLS_GET_INDEX_TABLE_OPS, "index", "get firmware version"},
    {TOOLS_AUTO_ENROLL_OPS, "enroll", "auto enroll"},
    {TOOLS_AUTO_IDENTIFY_OPS, "identify", "auto identify"},
    {TOOLS_EXIT_OPS, "exit", "program exit"}
}

static void ofp_display_help(void)
{
    int32_t i = 0;
    for (i=0; i<TOOLS_OPS_MAX; i++) {
        printf("input:%s  usage: %s\n", g_ofp_tool_operation[i].ops_name, g_ofp_tool_operation[i].description);
    }
}


static int32_t ofp_get_index_table(void)
{
    int32_t ret = 0;
    uint8_t page_number = 0;
    ofp_index_table table = {0};
    int i = 0;
    ret = ofp_usb_read_index_table(&(g_ofp_dev->usb_handle), page_number, &table);
    if (ret < 0) {
        OFP_LOGE("ofp_get_index_table ---> ofp_usb_read_index_table error \n");
        return ret;
    }
    printf("ofp index table: \n");
    for (i = 0; i < OFP_INDEX_TABLE_MAX; i++) {
        printf("0x%02x ", table.fp_index[i]);
    }
    printf("\n");
    return ret;
}


static int32_t ofp_get_firmware_version(void)
{
    ofp_firmware_version  fw_ver = {0};
    int32_t ret = 0;
    ret = ofp_usb_get_firmware_version(&(g_ofp_dev->usb_handle), &fw_ver);
    if (ret < 0) {
        OFP_LOGE("ofp_get_firmware_version ---> ofp_usb_get_firmware_version error \n");
        return ret;
    }
    printf("firmware_version: %s \n", fw_ver.firmware_version);
    return ret;
}


static int32_t ofp_find_next_enroll_id(ofp_index_table *table, uint8_t *is_finded)
{
    int32_t ret = 0;
    uint8_t page_number = 0;
    int i = 0;
    int j = 0;
    ofp_drv_driver_param_conf drpc = g_ofp_dev->drv_cfg.driver_param_conf;

    ret = ofp_usb_read_index_table(&(g_ofp_dev->usb_handle), page_number, table);
    if (ret < 0) {
        OFP_LOGE("ofp_usb_read_index_table error code:%d  \n", ret);
        return ret;
    }

    for(i = 0; i < OFP_INDEX_TABLE_MAX; i++)
    {
        for(j = 0; j < OFP_LEN_8; j++)
        {
            if((drpc.enroll_min_id <= (i * 8 + j)) \
                && (drpc.enroll_max_id >= (i*8 + j)))
            {
                if ((*is_finded == 0) && (((table->fp_index[i] >> j) & 0x01) == 0x00)) {
                    table->fp_next_enroll_id = i * 8 + j;
                    *is_finded = 1;
                }

                if (((table->fp_index[i] >> j) & 0x01) == 0x01) {
                    table->fp_enrolled_number++;
                }
            }
        }
    }


    return ret;
}

static int32_t ofp_auto_enroll(void)
{
    ofp_index_table table = {0};
    int32_t ret = 0;
    ofp_drv_driver_param_conf drpc = g_ofp_dev->drv_cfg.driver_param_conf;
    uint8_t is_finded = 0;
    ofp_enroll_result result = {0};
    ofp_enroll_input_setting in_set = {0};

    ret = ofp_find_next_enroll_id(&table, &is_finded);
    if ((ret < 0) || (is_finded != 1)) {
        OFP_LOGE("ofp_find_next_enroll_id ret code:%d is_finded:%d \n",ret, is_finded);
        return ret;
    }

    in_set.id = table.fp_next_enroll_id;
    in_set.times = drpc.enroll_times;
    in_set.param = 0;
    ret = ofp_usb_auto_enroll(&(g_ofp_dev->usb_handle), in_set, &result);
    if (ret < 0) {
        OFP_LOGE("ofp_auto_enroll ---> ofp_usb_auto_enroll error code ret:%d \n", ret);
        return ret;
    }

    while (1) {
        ret = ofp_usb_get_enroll_result(&(g_ofp_dev->usb_handle), &result);
        if (ret < 0) {
            OFP_LOGE("ofp_auto_enroll ---> ofp_usb_get_enroll_result error code ret:%d \n", ret);
            //return ret;
        }
        usleep(30 * 1000);
    }
    return ret;
}

static int32_t ofp_auto_identify(void)
{
    int32_t ret = 0;
    ofp_drv_driver_param_conf drpc = g_ofp_dev->drv_cfg.driver_param_conf;
    ofp_identify_result result = {0};
    ofp_identify_input_setting in_set = {0};

    in_set.fp_id = 0xffff;
    in_set.secure_level = 3;
    in_set.system_id = drpc.system_id;
    ret = ofp_usb_auto_identify(&(g_ofp_dev->usb_handle), in_set, &result);
    if (ret < 0) {
        OFP_LOGE("ofp_auto_identify ---> ofp_usb_auto_identify error code: %d \n", ret);
        return -3;
    }

    while(1) {

        ret = ofp_usb_get_identify_result(&(g_ofp_dev->usb_handle), &result);
        if (ret < 0) {
            OFP_LOGE("ofp_auto_identify --> ofp_usb_get_identify_result error code ret:%d \n", ret);
            //return ret;
        }
        usleep(20 * 1000);
    }

    return ret;
}

static int32_t ofp_usb_drv_init(ofp_dev *dev)
{
    int32_t ret = 0;
    ofp_drv_device_param_conf *dpc = &(dev->drv_cfg.device_param_conf);

    ret = uapi_usb_init();
    if (ret < 0) {
        OFP_LOGE("ofp_usb_drv_init ---> uapi_usb_init error \n");
        return -3;
    }
    ret = uapi_open_usb_handle_by_vid(dpc->usb_vid, &(dev->usb_handle));
    if (ret < 0) {
        OFP_LOGI("uapi_open_usb_handle_by_vid   vendor_id failed\n");
        uapi_close_usb_handle(&(dev->usb_handle));
        return -4;
    }

    return ret;
}


static int32_t ofp_parse_input(char * input)
{
    int32_t i = 0;
    for (i = 0; i < TOOLS_OPS_MAX; i++) {
        if (strcmp(g_ofp_tool_operation[i].ops_name, input) != 0) {

            return i;
        }
    }

    return TOOLS_OPS_MAX;
}

static void ofp_storage_add_fp(sqlite3 *db, char* uid, int enroll_id)
{
    //数据库增删改查
	feature_info *info;
	char buf[1024] = {0};
    char *drv_name = g_ofp_dev->drv_cfg.driver_param_conf.driver_name;
    int biotype = 0;
	// 创建特征结构体
	int idx = ofp_get_empty_index (db, drv_name, biotype, uid, 0, -1);
	info = ofp_new_feature_info (uid, biotype, drv_name, idx, "指纹");
	// 创建新的采样结构体
	info->sample = ofp_new_feature_sample(-1, NULL);
	info->sample->no = enroll_id;
	info->sample->data = buf;//bio_sto_new_str (feature_encode);
	// 打印特征结构体
	//print_feature_info (info);

	// 保存特征信息链表
	ofp_set_feature_info (db, info);

	// 回收特征数据项
	info->sample->data = NULL;

	ofp_free_feature_info_list (info);

}

static void ofp_storage_del_fp(sqlite3 *db, char* uid, int enroll_id)
{
    int biotype = 0;

    int ret = -1;
    char *drv_name = g_ofp_dev->drv_cfg.driver_param_conf.driver_name;
    //数据库增删改查
    ret = ofp_clean_feature_info (db, uid, biotype,
    	drv_name, 0, 0);
    return ret;
}


static void ofp_storage_change_fp()
{

}

static int32_t ofp_storage_test(void)
{
    int ret = 0;

	/* 检测并升级数据库 */
	sqlite3 *db = ofp_connect_db();
	ret = ofp_check_and_upgrade_db_format(db);
	if (ret != 0 )
	{
		ofp_disconnect_db(db);
		return -1;
	}

    /* 增加指纹*/
    ofp_storage_add_fp()


    ofp_disconnect_db(db);
    return 0
}

int main(int argc, char** argv)
{
    int ret = 0;
    int exit_flag = 0;
    char input[100] = {0};
    OFP_LOGI("%s \n", OFP_TOOLS_VERSION);
    int32_t i = 0;;

    g_ofp_dev = bio_dev_new();

    ret = ofp_dev_open_drv_config(&(g_ofp_dev->drv_cfg), OFP_DRIVER_CONFIG_FILE);
    if (ret < 0) {
        OFP_LOGE("tools ofp_dev_open_drv_config error \n");
        return -1;
    }

    ret = ofp_dev_get_drv_config(&(g_ofp_dev->drv_cfg));
    if (ret < 0) {
        OFP_LOGE("tools ofp_dev_get_drv_config error code:%d \n", ret);
        return -2;
    }

    ret = ofp_usb_drv_init(g_ofp_dev);
    if (ret < 0) {
        OFP_LOGE("tools ofp_usb_drv_init error code:%d \n", ret);
        return -3;
    }

    while (1) {
        printf("please Input Operation:");
        scanf("%s", input);
        i = ofp_parse_input(input);

        switch(i) {
            case TOOLS_HELP_OPS:
                ofp_display_help();
            break;
            case TOOLS_GET_FIRMWARE_VERSION_OPS:
                ret = ofp_get_firmware_version();
            break;
            case TOOLS_GET_INDEX_TABLE_OPS:
                ret = ofp_get_index_table();
            break;
            case TOOLS_AUTO_ENROLL_OPS:
                ret = ofp_auto_enroll();
                break;
            case TOOLS_AUTO_IDENTIFY_OPS:
                ret = ofp_auto_identify();
                break;
            case TOOLS_STORAGE_OPS:
                break;
            case TOOLS_EXIT_OPS:
                exit_flag = 1;
            default:
                break;
        }

        if (exit_flag == 1) {
            break;
        }
    }

    uapi_close_usb_handle(&(g_ofp_dev->usb_handle));
    uapi_usb_exit();

    ofp_dev_close_drv_config(&(g_ofp_dev->drv_cfg));
    bio_dev_free(g_ofp_dev);

    return ret;
}
